package org.hxzon.tapestry5.components;

import java.util.ArrayList;
import java.util.List;

import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.services.Request;
import org.hxzon.tapestry5.components.base.AbstractFieldEx;
import org.hxzon.tapestry5.model.TreeModel;
import org.hxzon.tapestry5.model.ValueIsSelected;
import org.hxzon.tapestry5.model.ValueLabel;
import org.hxzon.tapestry5.util.TapestryEx;

public class CheckboxTree extends AbstractFieldEx {

    @Parameter(name = "value", required = true)
    private List<Object> _value;

    @Parameter(name = "source", required = true, allowNull = false)
    private List<Object> _source;

    @Parameter(name = "valueIsSelected")
    private ValueIsSelected<Object> _valueIsSelected;

    @Parameter(name = "treeModel", required = true, allowNull = false)
    private TreeModel<Object> _treeModel;

    @Parameter(name = "valueLabel")
    private ValueLabel<Object> _valueLabel;

    @Parameter(name = "labelFirst", value = "false")
    private boolean _labelFirst;

    @Parameter(name = "readonly", value = "false")
    private boolean _readonly;

    @Parameter(name = "itemClass", defaultPrefix = BindingConstants.LITERAL)
    private String _itemClass;

    @Inject
    private Request _request;

    @Inject
    private ComponentResources _resources;

    @BeginRender
    void begin(MarkupWriter writer) {
        writeTitle(writer);
        //
        String clientId = getClientId();
        String ctrlName = getControlName();
        writer.element("ul");
        _resources.renderInformalParameters(writer);
        writeTreeNode(writer, _treeModel.getRoot(), clientId, ctrlName);
        writer.end();
    }

    private void writeTreeNode(MarkupWriter writer, Object curValue, String clientId, String ctrlName) {
        int globalIndex = _source.indexOf(curValue);
        //
        boolean checked = false;
        if (_valueIsSelected != null) {
            checked = _valueIsSelected.isSelected(curValue);
        } else if (_value != null) {
            checked = _value.contains(curValue);
        }
        //
        String valueLabel = null;
        if (_valueLabel != null) {
            valueLabel = _valueLabel.toLabel(curValue, globalIndex);
        } else {
            valueLabel = curValue.toString();
        }
        writer.element("li");
        writeCheckbox(writer, (clientId + "_" + globalIndex), ctrlName, checked, globalIndex, valueLabel, _labelFirst, _itemClass);
        boolean hasChild = _treeModel.hasChildren(curValue);
        if (hasChild) {
            writer.element("ul");
            for (Object child : _treeModel.getChildren(curValue)) {
                writeTreeNode(writer, child, clientId, ctrlName);
            }
            writer.end();
        }
        writer.end();
    }

    private void writeCheckbox(MarkupWriter writer, String clientId, String ctrlName, boolean checked,//
            int index, String label, boolean labelFirst, String itemClass) {
        //boolean drawItem = itemClass != null;
        boolean drawItem = true;
        if (drawItem) {
            writer.element("span", "class", buildItemClass(itemClass, checked));
        }
        if (labelFirst) {
            writer.element("label", "for", clientId);
            writer.write(label);
            writer.end();
        }
        writer.element("input", "type", "checkbox", "name", ctrlName, "id", clientId, //
                "checked", checked ? "checked" : null, "value", index, "disabled", _readonly ? "disabled" : null);
        writer.end();
        if (!labelFirst) {
            writer.element("label", "for", clientId);
            writer.write(label);
            writer.end();
        }
        if (drawItem) {
            writer.end();
        }
    }

    private String buildItemClass(String itemClass, boolean checked) {
        List<String> classes = CollectionFactory.newList();

        if (itemClass != null) {
            classes.add(itemClass);
        }
        if (checked) {
            classes.add(TapestryEx.Css_CheckboxOrigChecked);
        }
        return TapestryInternalUtils.toClassAttributeValue(classes);
    }

    @AfterRender
    void after(MarkupWriter writer) {

    }

    @Override
    protected void processSubmission(String controlName) {

        String[] postedValues = _request.getParameters(controlName);
        if (postedValues == null || postedValues.length == 0) {
            if (_value != null) {
                _value.clear();
            }
            return;
        }
        List<Object> result = new ArrayList<Object>();
        for (String postedValue : postedValues) {
            result.add(_source.get(Integer.valueOf(postedValue)));
        }
        if (_value == null) {
            _value = result;
        } else {
            _value.clear();
            _value.addAll(result);
        }
    }

}